﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Kokomo.Mirror.PeFormat;
using System.IO;
using Kokomo.Mirror.Ia32;

namespace Kokomo.Mirror.Test
{
	/// <summary>
	/// Summary description for Ia32Test
	/// </summary>
	[TestClass]
	public class Ia32Test
	{
		public Ia32Test()
		{
			//
			// TODO: Add constructor logic here
			//
		}

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		// [TestInitialize()]
		// public void MyTestInitialize() { }
		//
		// Use TestCleanup to run code after each test has run
		// [TestCleanup()]
		// public void MyTestCleanup() { }
		//
		#endregion

		[TestMethod]
		public void OpCodesTest()
		{
			MemoryStream instructionStream = new MemoryStream();
			BinaryWriter writer = new BinaryWriter(instructionStream);
			writer.Write(new byte[] { 0x00, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(new byte[] { 0x01, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(new byte[] { 0x02, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(new byte[] { 0x03, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(new byte[] { 0x04, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(new byte[] { 0x05, ModRM.FromModRMNnn((int)Mod.None, (int)AddressingForm32.eax, Registers.EAX.Number).Value });
			writer.Write(0x06);
			writer.Write(0x07);


		}

		[TestMethod]
		public void Ia32ReaderTest()
		{
			string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "shell32.dll");
			PeModule shell32 = PeModule.Open(path);

			SectionHeader codeSection = shell32.Headers.FindSectionByName(".text");
			byte[] codeData = shell32.ReadSectionData(".text");

			uint entryPointRva = shell32.Headers.OptionalHeader.AddressOfEntryPoint;
			uint entryPointOffset = shell32.Headers.RvaToFile(entryPointRva).Value - codeSection.PointerToRawData;

			MemoryStream stream = new MemoryStream(codeData);
			stream.Position = entryPointOffset;

			NativeProcedureInfo procedure = shell32.GetProcedureAtRva(codeSection.VirtualAddress);
			Ia32Disassembly disassembly = Ia32Disassembler.Disassemble(procedure);

			//shell32.DiscoverProcedures();

			//List<Ia32Record> records = new List<Ia32Record>();
			//Ia32Reader reader = new Ia32Reader(stream, (int));

			//int recordCount = 100;
			//while (
			//    reader.MoveNext()
			//    && (records.Count < recordCount)
			//    )
			//{
			//    Ia32Record record = reader.CurrentRecord;
			//    records.Add(record);
			//}

		}
	}
}
